/*
 * @Author: HZK
 * @Date: 2020-08-26 11:08:50
 * @LastEditTime: 2020-08-26 13:20:53
 * @LastEditors: hanfengmi
 * @Description: 
 */

/** 手写promise
 * 1.一个类,在执行这个类时，需要传一个执行器，执行器会立即执行
 * 2.promise三种状态及改变 pending -> fullfilled; pending -> rejected
 * 3.resolve和reject是用来更改状态的
 * 4.then内部做的事情就是判断状态, **then方法是被定义在原型对象中的**
 * 5.then记录成功的值和失败的原因
 * 6.链式调用，传值
 * 
 * 简单的promise实现
 * 第五步：then方法返回另一个个promise，需要判断返回值
 *
 */
const PENDING = 'pending'; // 等待
const FULLFILLED = 'fullfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
    constructor(executor){
        // 执行器立即执行
        executor(this.resolve,this.reject) 
    }
    status = PENDING; // 初始状态 默认pending
    value = undefined;// 成功的值
    reason = undefined; // 失败的原因
    successCallback = [] // 成功回调 2.为异步任务准备 3.变成数组解决多次调用问题
    failCallback = [] // 失败回调 2.为异步任务准备 3.变成数组解决多次调用问题
    resolve= value => { // this指向问题！
        if(this.status !== PENDING) return // 状态pending 才可修改
        this.status = FULLFILLED; // 修改promise状态 成功 一旦确定就不可更改
        this.value = value; // 保存成功之后的值
        // 2.成功回调是否存在
        // this.successCallback && this.successCallback(value)
        // 3.循环数组调用 从前往后执行 获取第一个并在数组中删除
        while (this.successCallback.length){
            this.successCallback.shift()(value)
        }
    }

    reject= reason => {
        if(this.status !== PENDING) return // 状态pending 才可修改
        this.status = REJECTED;// 修改promise状态 成功 一旦确定就不可更改
        this.reason = reason;
        // 2.失败回调是否存在
        // this.failCallback && this.failCallback(reason)
        // 3.循环数组调用 从前往后执行 获取第一个并在数组中删除
        while (this.failCallback.length){
            this.failCallback.shift()(reason)
        }
    }

    then(successCallback,failCallback){// 定义在原型对象之中 ？？？？
        //判断状态
        // 4.需要返回promise 才能实现链式调用
        const promise2 = new MyPromise((resolve,reject)=>{
            if(this.status === FULLFILLED){ // 成功
                let x = successCallback(this.value) // 4.拿到成功回调的返回值
                // 5.如果x是普通值，直接调用resolve
                // 5.如果x是promise, 查看promise对象返回结果
                // 5.再根据返回结果判断是使用resolve还是reject
                // resolve(x) 写成公共函数 resolvePromise
                resolvePromise(x,resolve,reject)
            }else if(this.status === REJECTED){ // 失败
                failCallback(this.reason)
            }else { // 2.等待状态 3.push到数组中
                this.successCallback.push(successCallback);
                this.failCallback.push(failCallback);
            }
        })

        return promise2 // 实现then 链式调用 
    }
}

// 5.
function resolvePromise (x,resolve,reject) {
    if(x instanceof MyPromise){// promise对象
        // x.then(value=>resolve(value),reason=>reject(reason))
        x.then(resolve,reject)
    }else {
        resolve(x)
    }
}

export default MyPromise